home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The Atari Compendium
/
The Atari Compendium (Toad Computers) (1994).iso
/
files
/
umich
/
music
/
eked-m1.zoo
/
src
/
midi_com.c
< prev
next >
Wrap
C/C++ Source or Header
|
1995-02-19
|
10KB
|
434 lines
/*
* EKED-M1 : Editor for Korg M1 synth; midi_com.c : MIDI communications
* Copyright (C) 1995 Steven M. Eker (Steven.Eker@brunel.ac.uk)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <stddef.h>
#include <osbind.h>
#include <gemfast.h>
#include <aesbind.h>
#include "eked-m1.h"
#include "midi.h"
#include "gm/gem_man.h"
#include "defs.h"
#include "types.h"
#include "externs.h"
#define TIME_OUT_REP 50
#define TIME_OUT (-1)
#define BAD_REPLY (-2)
static BYTE big[7 + PD_SIZE];
static BYTE small[7];
static int global_channel = 0;
static enum {
SYSEX_OFF,
SYSEX_EXP,
SYSEX_LIVE
} sysex_mode = SYSEX_LIVE;
void midi_opt()
{
OBJECT *midi_options;
int channel, t;
rm_gaddr(R_TREE, MIDI_OPTIONS, &midi_options);
GM_SELECT(sysex_mode == SYSEX_OFF, midi_options, MO_OFF);
GM_SELECT(sysex_mode == SYSEX_EXP, midi_options, MO_EXP);
GM_SELECT(sysex_mode == SYSEX_LIVE, midi_options, MO_LIVE);
channel = global_channel + 1;
unum_update(midi_options + MO_CHANNEL, channel);
fm_begin_dialog(midi_options, 0);
do{
t = fm_run_dialog();
if(t == MO_CHANNEL)
channel = fm_roll(midi_options, t, channel, 1, 16, &unum_update);
}while(t != MO_OK && t != MO_CANCEL);
fm_end_dialog();
if(t == MO_CANCEL)
return;
if(midi_options[MO_OFF].ob_state & SELECTED)
sysex_mode = SYSEX_OFF;
else if(midi_options[MO_EXP].ob_state & SELECTED)
sysex_mode = SYSEX_EXP;
else
sysex_mode = SYSEX_LIVE;
global_channel = channel - 1;
}
int midi_comm(int send_bytes, BYTE *send_buf, int rec_bytes, BYTE *rec_buf)
{
volatile _IOREC *p = Iorec(2);
int s, d, t;
BYTE b;
p->ibufhd = p->ibuftl = 0;
Midiws(send_bytes - 1, send_buf);
t = 0;
do{
while(p->ibufhd == p->ibuftl){ /* while buffer empty */
evnt_timer(20L); /* wait 20ms - about 63 MIDI bytes */
if(t++ == TIME_OUT_REP)
return TIME_OUT;
}
s = p->ibufhd + 1;
if(s >= p->ibufsiz)
s = 0;
b = (p->ibuf)[s];
p->ibufhd = s;
if(!real_time(b)) /* disregard real time messages */
t = 0;
}while(b != (BYTE) SYSEX); /* until start of sysex message */
rec_buf[0] = b;
t = 0;
d = 1;
do{
if(d == rec_bytes) /* reply overran rec_buf */
return BAD_REPLY;
while(p->ibufhd == p->ibuftl){ /* while buffer empty */
evnt_timer(20L); /* wait 20ms - about 63 MIDI bytes */
if(t++ == TIME_OUT_REP)
return TIME_OUT;
}
s = p->ibufhd + 1;
if(s >= p->ibufsiz)
s = 0;
b = (p->ibuf)[s];
p->ibufhd = s;
if(!real_time(b)){ /* disregard real time messages */
rec_buf[d++] = b;
t = 0;
}
}while(data_byte(b)); /* until end of sysex message */
return d;
}
int m1_sysex(int send_bytes, BYTE *send_buf, int rec_bytes, BYTE *rec_buf)
{
int t;
send_buf[0] = SYSEX;
send_buf[1] = KORG_ID;
send_buf[2] = FORMAT_ID | global_channel;
send_buf[3] = M1_ID;
send_buf[send_bytes - 1] = EOX;
for(;;){
t = midi_comm(send_bytes, send_buf, rec_bytes, rec_buf);
if(t == rec_bytes){
if(rec_buf[4] == DATA_LOAD_ERR)
t = DATA_LOAD_ALERT;
else
break;
}
else{
switch(t){
case TIME_OUT:
t = NO_RESPOND_ALERT;
break;
case BAD_REPLY:
t = BAD_REPLY_ALERT;
break;
default:
t = BAD_LEN_ALERT;
}
}
if(fm_alert(1, t) == 2)
return FAILURE;
}
return SUCCESS;
}
int tx_bank(BANK *bank, int flags)
{
int mode;
if(sysex_mode == SYSEX_OFF)
return FAILURE;
small[4] = MODE_REQ;
if(m1_sysex(6, small, 10, big) == FAILURE)
return FAILURE;
if(flags & TX_CARD){
switch(big[7] >> 4){
case 0:
fm_alert(1, NO_CARD_ALERT);
return FAILURE;
case 1:
fm_alert(1, ROM_CARD_ALERT);
return FAILURE;
case 3:
fm_alert(1, PROT_CARD_ALERT);
return FAILURE;
}
mode = big[7] & 0x03;
if(mode == 2){
fm_alert(1, SEQ_CARD_ALERT);
return FAILURE;
}
big[5] = 1;
}
else{
mode = big[6];
big[5] = 0;
}
if(flags & TX_GLOB){
big[4] = GLOBAL_DATA_DUMP;
byte2korg(big + 6, bank->data, GLOBAL_SIZE);
if(m1_sysex(7 + GD_SIZE, big, 6, small) == FAILURE)
return FAILURE;
}
if(flags & TX_COMB){
big[4] = ALL_COMB_DUMP;
big[5] |= mode << 1;
byte2korg(big + 6, bank->data + GLOBAL_SIZE,
mode ? (50 * COMBINATION_SIZE) : (100 * COMBINATION_SIZE));
if(m1_sysex(mode ? (7 + CD50_SIZE) : (7 + CD_SIZE), big, 6, small)
== FAILURE)
return FAILURE;
}
if(flags & TX_PROG){
big[4] = ALL_PROG_DUMP;
big[5] |= mode << 1;
byte2korg(big + 6, bank->data + PROGRAM_OFFSET,
mode ? (50 * PROGRAM_SIZE) : (100 * PROGRAM_SIZE));
if(m1_sysex(mode ? (7 + PD50_SIZE) : (7 + PD_SIZE), big, 6, small)
== FAILURE)
return FAILURE;
}
return SUCCESS;
}
int rx_bank(BANK *bank, int flags)
{
int mode;
if(sysex_mode == SYSEX_OFF)
return FAILURE;
small[4] = MODE_REQ;
if(m1_sysex(6, small, 10, big) == FAILURE)
return FAILURE;
if(flags & TX_CARD){
if(!(big[7] & 0x30)){
fm_alert(1, NO_CARD_ALERT);
return FAILURE;
}
mode = big[7] & 0x03;
if(mode == 2){
fm_alert(1, SEQ_CARD_ALERT);
return FAILURE;
}
small[5] = 1;
}
else{
mode = big[6];
small[5] = 0;
}
if(flags & TX_GLOB){
small[4] = GLOBAL_DATA_REQ;
if(m1_sysex(7, small, 7 + GD_SIZE, big) == FAILURE)
return FAILURE;
korg2byte(bank->data, big + 6, GLOBAL_SIZE);
}
if(flags & TX_COMB){
small[4] = ALL_COMB_REQ;
if(m1_sysex(7, small, mode ? (7 + CD50_SIZE) : (7 + CD_SIZE), big)
== FAILURE)
return FAILURE;
korg2byte(bank->data + GLOBAL_SIZE, big + 6,
mode ? (50 * COMBINATION_SIZE) : (100 * COMBINATION_SIZE));
}
if(flags & TX_PROG){
small[4] = ALL_PROG_REQ;
if(m1_sysex(7, small, mode ? (7 + PD50_SIZE) : (7 + PD_SIZE), big)
== FAILURE)
return FAILURE;
korg2byte(bank->data + PROGRAM_OFFSET, big + 6,
mode ? (50 * PROGRAM_SIZE) : (100 * PROGRAM_SIZE));
}
return SUCCESS;
}
int tx_para_chg(int page, int pos, int value)
{
if(sysex_mode != SYSEX_LIVE || page < 0)
return FAILURE;
big[4] = PARAMETER_CHANGE;
big[5] = page;
big[6] = pos;
big[7] = value & 0x7F;
big[8] = (value >> 7) & 0x7F;
return m1_sysex(10, big, 6, small);
}
int tx_prog_dmp(BYTE *prog)
{
if(sysex_mode != SYSEX_LIVE)
return FAILURE;
big[4] = PROG_DUMP;
byte2korg(big + 5, prog, PROGRAM_SIZE);
return m1_sysex(170, big, 6, small);
}
int tx_comb_dmp(BYTE *comb)
{
if(sysex_mode != SYSEX_LIVE)
return FAILURE;
big[4] = COMB_DUMP;
byte2korg(big + 5, comb, COMBINATION_SIZE);
return m1_sysex(148, big, 6, small);
}
int tx_mode_chg(int mode)
{
if(sysex_mode != SYSEX_LIVE)
return FAILURE;
big[4] = MODE_CHANGE;
big[5] = mode;
big[6] = 0x10;
return m1_sysex(8, big, 6, small);
}
void tx_prog_chg(int number)
{
if(sysex_mode != SYSEX_LIVE) /* not a sysex but we treat it as such */
return;
/*
* M1 sometimes ignores program change following closely on the heels of
* a sysex so pause for 50ms.
*/
evnt_timer(50